import { HTTPException } from '../http-exception';
import {
  storedAgentIdPathParams,
  listStoredAgentsQuerySchema,
  createStoredAgentBodySchema,
  updateStoredAgentBodySchema,
  listStoredAgentsResponseSchema,
  getStoredAgentResponseSchema,
  createStoredAgentResponseSchema,
  updateStoredAgentResponseSchema,
  deleteStoredAgentResponseSchema,
} from '../schemas/stored-agents';
import { createRoute } from '../server-adapter/routes/route-builder';

import { handleError } from './error';

// ============================================================================
// Route Definitions
// ============================================================================

/**
 * GET /api/stored/agents - List all stored agents
 */
export const LIST_STORED_AGENTS_ROUTE = createRoute({
  method: 'GET',
  path: '/api/stored/agents',
  responseType: 'json',
  queryParamSchema: listStoredAgentsQuerySchema,
  responseSchema: listStoredAgentsResponseSchema,
  summary: 'List stored agents',
  description: 'Returns a paginated list of all agents stored in the database',
  tags: ['Stored Agents'],
  handler: async ({ mastra, page, perPage, orderBy }) => {
    try {
      const storage = mastra.getStorage();

      if (!storage) {
        throw new HTTPException(400, { message: 'Storage is not configured' });
      }

      if (!storage.supports.agents) {
        throw new HTTPException(400, { message: 'Storage does not support agents' });
      }

      const result = await storage.listAgents({
        page,
        perPage,
        orderBy,
      });

      return result;
    } catch (error) {
      return handleError(error, 'Error listing stored agents');
    }
  },
});

/**
 * GET /api/stored/agents/:storedAgentId - Get a stored agent by ID
 */
export const GET_STORED_AGENT_ROUTE = createRoute({
  method: 'GET',
  path: '/api/stored/agents/:storedAgentId',
  responseType: 'json',
  pathParamSchema: storedAgentIdPathParams,
  responseSchema: getStoredAgentResponseSchema,
  summary: 'Get stored agent by ID',
  description: 'Returns a specific agent from storage by its unique identifier',
  tags: ['Stored Agents'],
  handler: async ({ mastra, storedAgentId }) => {
    try {
      const storage = mastra.getStorage();

      if (!storage) {
        throw new HTTPException(400, { message: 'Storage is not configured' });
      }

      if (!storage.supports.agents) {
        throw new HTTPException(400, { message: 'Storage does not support agents' });
      }

      const agent = await storage.getAgentById({ id: storedAgentId });

      if (!agent) {
        throw new HTTPException(404, { message: `Stored agent with id ${storedAgentId} not found` });
      }

      return agent;
    } catch (error) {
      return handleError(error, 'Error getting stored agent');
    }
  },
});

/**
 * POST /api/stored/agents - Create a new stored agent
 */
export const CREATE_STORED_AGENT_ROUTE = createRoute({
  method: 'POST',
  path: '/api/stored/agents',
  responseType: 'json',
  bodySchema: createStoredAgentBodySchema,
  responseSchema: createStoredAgentResponseSchema,
  summary: 'Create stored agent',
  description: 'Creates a new agent in storage with the provided configuration',
  tags: ['Stored Agents'],
  handler: async ({
    mastra,
    id,
    name,
    description,
    instructions,
    model,
    tools,
    defaultOptions,
    workflows,
    agents,
    inputProcessors,
    outputProcessors,
    memory,
    scorers,
    metadata,
  }) => {
    try {
      const storage = mastra.getStorage();

      if (!storage) {
        throw new HTTPException(400, { message: 'Storage is not configured' });
      }

      if (!storage.supports.agents) {
        throw new HTTPException(400, { message: 'Storage does not support agents' });
      }

      // Check if agent with this ID already exists
      const existing = await storage.getAgentById({ id });
      if (existing) {
        throw new HTTPException(409, { message: `Agent with id ${id} already exists` });
      }

      // Only include tools if it's actually an array from the body (not {} from adapter)
      const toolsFromBody = Array.isArray(tools) ? tools : undefined;

      const agent = await storage.createAgent({
        agent: {
          id,
          name,
          description,
          instructions,
          model,
          tools: toolsFromBody,
          defaultOptions,
          workflows,
          agents,
          inputProcessors,
          outputProcessors,
          memory,
          scorers,
          metadata,
        },
      });

      return agent;
    } catch (error) {
      return handleError(error, 'Error creating stored agent');
    }
  },
});

/**
 * PATCH /api/stored/agents/:storedAgentId - Update a stored agent
 */
export const UPDATE_STORED_AGENT_ROUTE = createRoute({
  method: 'PATCH',
  path: '/api/stored/agents/:storedAgentId',
  responseType: 'json',
  pathParamSchema: storedAgentIdPathParams,
  bodySchema: updateStoredAgentBodySchema,
  responseSchema: updateStoredAgentResponseSchema,
  summary: 'Update stored agent',
  description: 'Updates an existing agent in storage with the provided fields',
  tags: ['Stored Agents'],
  handler: async ({
    mastra,
    storedAgentId,
    name,
    description,
    instructions,
    model,
    tools,
    defaultOptions,
    workflows,
    agents,
    inputProcessors,
    outputProcessors,
    memory,
    scorers,
    metadata,
  }) => {
    try {
      const storage = mastra.getStorage();

      if (!storage) {
        throw new HTTPException(400, { message: 'Storage is not configured' });
      }

      if (!storage.supports.agents) {
        throw new HTTPException(400, { message: 'Storage does not support agents' });
      }

      // Check if agent exists
      const existing = await storage.getAgentById({ id: storedAgentId });
      if (!existing) {
        throw new HTTPException(404, { message: `Stored agent with id ${storedAgentId} not found` });
      }

      // Only include tools if it's actually an array from the body (not {} from adapter)
      const toolsFromBody = Array.isArray(tools) ? tools : undefined;

      const agent = await storage.updateAgent({
        id: storedAgentId,
        name,
        description,
        instructions,
        model,
        tools: toolsFromBody,
        defaultOptions,
        workflows,
        agents,
        inputProcessors,
        outputProcessors,
        memory,
        scorers,
        metadata,
      });

      return agent;
    } catch (error) {
      return handleError(error, 'Error updating stored agent');
    }
  },
});

/**
 * DELETE /api/stored/agents/:storedAgentId - Delete a stored agent
 */
export const DELETE_STORED_AGENT_ROUTE = createRoute({
  method: 'DELETE',
  path: '/api/stored/agents/:storedAgentId',
  responseType: 'json',
  pathParamSchema: storedAgentIdPathParams,
  responseSchema: deleteStoredAgentResponseSchema,
  summary: 'Delete stored agent',
  description: 'Deletes an agent from storage by its unique identifier',
  tags: ['Stored Agents'],
  handler: async ({ mastra, storedAgentId }) => {
    try {
      const storage = mastra.getStorage();

      if (!storage) {
        throw new HTTPException(400, { message: 'Storage is not configured' });
      }

      if (!storage.supports.agents) {
        throw new HTTPException(400, { message: 'Storage does not support agents' });
      }

      // Check if agent exists
      const existing = await storage.getAgentById({ id: storedAgentId });
      if (!existing) {
        throw new HTTPException(404, { message: `Stored agent with id ${storedAgentId} not found` });
      }

      await storage.deleteAgent({ id: storedAgentId });

      return { success: true, message: `Agent ${storedAgentId} deleted successfully` };
    } catch (error) {
      return handleError(error, 'Error deleting stored agent');
    }
  },
});
